曾有位前輩分享了一篇 PO 文,內容是一張 Stack Overflow 回答後的截圖外加 Hashtag #工程師假日的浪漫,工程師的浪漫就是即便是假日都還是想逛逛 Stack Overflow 順手解掉幾個問題。在 IT 邦幫忙也有類似的互動,因此我們來運用前幾天分享的爬蟲結合 Line API 每天自動推播與自己設定相關的問題。
首先在技術問答的頁面中,我們可以看到幾個資訊:「問題」、「問題相關 Tag」、「題問時間」、「提問人」、「預覽數」、「回答數」、「是否有最佳解答」、「Like 數」等,今天的目的是為「蒐集近期自己關心的主題且該問題還尚未被解決」,那就應該專注在「問題相關的 Tag」、「是否有最佳解答」與「提問時間」的分析。而從符合上述條件的問題,將會擷取他的問題標題與 URL 透過 Line API 推播給自己。
由於整個流程可以切割為爬蟲與 Line API 串接,因此這次的番外篇會分成兩天,第一天是關於爬蟲程式的修改,第二天是利用 Flask 框架 + Line SDK 做一個簡單的推播媒介。
擷取昨天部分的程式碼,並做適當的編改。首先由於這次要滿足多個條件,因此必須在更上層的 HTML 標籤開始定位(xpath = "//div[@class = 'qa-list']"
)往下一層層的定位出各個條件。
雖然時間層面只會爬取今天+昨天的問題,但還是要去定位出最後一頁的數字為多少,因為在爬蟲前無法確定這樣的時間區段會佔多少的頁面內容。因此在程式的一開始執行 page_numbers
定位出最後一頁的數字。
再來要符合第一個條件該問題尚未有“最佳解答”,已有最佳解答的問題,在回答欄位會是橘色底的方式呈現,而觀察 HTML 會發現同樣的 <a>
標籤多出了 qa-condition--had-answer
這個 class。我們可以利用這個作為區分。
第二個條件是符合相關的 Tag,這裡簡單設定目標 Tag 為 python,可以透 find
的方式在這個 HTML 節點(xpath = "//div[@class = 'qa-list']"
)往下定位。
第三個條件為提問時間,一樣透過 find
的方式往下定位置時間的位置。
from time import sleep
import datetime
import requests
from lxml import etree
def page_numbers(url):
response = requests.get(url)
html = etree.HTML(response.text)
next_tag = html.xpath("//a[@rel='next']")[0] # 定位出下一頁
final_page = next_tag.getparent().getprevious().find('a').text # 下一頁按鈕的前一個按鈕及為最後一頁的數字
return int(final_page)
def get_title_url(html,target_date):
element_list = html.xpath("//div[@class = 'qa-list']")
answered_tag = "qa-condition qa-condition--has-answer qa-condition--had-answer " # 已有最佳解答
target_date = target_date.strftime("%Y-%m-%d")
articles = {}
for element in element_list:
tags = [t.text for t in element.findall("./div[@class = 'qa-list__content']/div[@class='qa-list__tags']/a")] # 列出所有 Tag
time = element.find("./div[@class = 'qa-list__content']/div[@class='qa-list__info']/a[1]").text # 定位出時間
answer_status = element.find("./div[@class = 'qa-list__condition']/a[2]").get('class') # 找出回答標籤的 class 內容
if answer_status != answered_tag and "python" in tags and time == target_date: # 若三個條件皆符合,則收入為目標問題
articles[element.find("./div[@class = 'qa-list__content']/h3/a").text] = element.find("./div[@class = 'qa-list__content']/h3/a").get("href")
return articles
target_url = "https://ithelp.ithome.com.tw/questions"
today = datetime.date.today()
target_date = today.replace(day=today.day -1)
last_page = page_numbers(target_url)
articles = {}
for page in range(last_page):
response = requests.get(target_url,params = {'page':page+1})
html = etree.HTML(response.text)
articles = {**articles,**get_title_url(html,target_date)}
last_question_date = html.xpath("//div[@class='qa-list__info']/a[1]")[-1].text
if datetime.datetime.strptime(last_question_date,"%Y-%m-%d").date() < target_date:
break
完成爬蟲後,明天將透過 Line API 的串接,達成每日接收新問題的小工具。明天見!